namespace FIREFLYX {
    /**
     * 复用的数组,适用于重复创建数组容器的场景,减少GC的消耗.
     * (实际上 arr.length = 0 , 不会分配新的内存，设计意义需要重新考虑了。)
     */
    export class ReuseArray<T>{
        private array: Nullable<T>[];
        private buoy = -1;
        /** 真的完全清理（效率更低）,建议存储基础值类型数据时关闭 */
        private reallyClear: boolean;

        /**
         * 复用数组
         * @param reallyClear 真的完全清理（效率更低）,建议存储基础值类型数据时关闭
         * @param items 初始数据
         */
        constructor(reallyClear = true, items?: T[]) {
            this.reallyClear = reallyClear;
            this.array = items != null ? items : [];
            this.buoy = this.array.length - 1;
        }

        /** 获取原始数组 对象 */
        public getRawArray() { return this.array; }

        /** 当前使用长度 */
        public get length() { return this.buoy + 1; }
        public set length(val) { this.buoy = val - 1; }

        /**
         * 添加元素到有效的尾部()位置, length 增加1 
         * @param val 值
         */
        public push(val: Nullable<T>) {
            this.buoy++;
            this.array[this.buoy] = val;
        }

        /**
         * 获取指定索引的值
         * @param index 索引
         * @returns 值
         */
        public get(index: number) {
            if (index > this.buoy) return null;
            return this.array[index];
        }

        /**
         * 设置指定索引的值
         * @param index 索引
         * @param val 值
         */
        public set(index: number, val: Nullable<T>) {
            if (index > this.buoy) return;
            this.array[index] = val;
        }

        /** 数组所有值置为null  */
        public clear() {
            const len = this.array.length;
            if (this.reallyClear) {
                for (let i = 0; i < len; i++) {
                    if (this.array[i] == null && i >= this.buoy) break;
                    this.array[i] = null;
                }
            }
            this.buoy = -1;
        }

        /**
         * 克隆一个数组
         * @returns 克隆的数组对象
         */
        public clone(): ReuseArray<T> {
            const result = new ReuseArray<T>();
            if (this.length != 0) {
                result.array = this.array.concat();
                result.length = result.array.length = this.length;
            }
            return result;
        }

        /**
         * 从一个数组复制数据
         */
        public copyFrom(arr: ReuseArray<T>) {
            if (!arr || arr == this) return;
            this.clear();
            const len = arr.length;
            const rawArr = arr.array;
            const myRawArr = this.array;
            for (let i = 0; i < len; i++) {
                myRawArr[i] = rawArr[i];
            }
            this.length = len;
        }

        /**
         * 就地排序数组。
         * @param compareFun 用于确定元素顺序的函数。
         * @returns 本数组
         */
        public sort(compareFun?: (a: Nullable<T>, b: Nullable<T>) => number) {
            const cFun = compareFun == null ? (a: Nullable<T>, b: Nullable<T>) => { return (a as any) - (b as any); } : compareFun;
            const _fun = (a: Nullable<T>, b: Nullable<T>) => {
                const val = cFun(a, b);
                if (isNaN(val) || val == null) return 0;
                return val;
            };
            const sort = (arr: ReuseArray<T>, left = 0, right = arr.length - 1) => {
                if (left >= right) {//如果左边的索引大于等于右边的索引说明整理完毕
                    return;
                }
                let i = left;
                let j = right;
                const baseVal = arr.get(j); // 取无序数组最后一个数为基准值
                while (i < j) {//把所有比基准值小的数放在左边大的数放在右边
                    while (i < j && _fun(arr.get(i), baseVal) <= 0) { //找到一个比基准值大的数交换
                        i++;
                    }

                    arr.set(j, arr.get(i));// 将较大的值放在右边如果没有比基准值大的数就是将自己赋值给自己（i 等于 j）
                    while (j > i && _fun(baseVal, arr.get(j)) <= 0) { //找到一个比基准值小的数交换
                        j--;
                    }
                    arr.set(i, arr.get(j));// 将较小的值放在左边如果没有找到比基准值小的数就是将自己赋值给自己（i 等于 j）
                }
                arr.set(j, baseVal);// 将基准值放至中央位置完成一次循环（这时候 j 等于 i ）
                sort(arr, left, j - 1); // 将左边的无序数组重复上面的操作
                sort(arr, j + 1, right); // 将右边的无序数组重复上面的操作
            };
            sort(this);
            return this;
        }
    }
    /** 对象池 */
    export class Pool<T>{
        private static readonly inPoolTag = "__INPOOL__";
        protected _poolList: T[];
        protected _size: number;
        protected _extendable: boolean;
        protected _type: new () => T;
        protected _onDelete: Nullable<(obj: T) => void> = null;
        /**
         * 初始化 对象池
         * @param type 池元素类型
         * @param initSize 初始化尺寸
         * @param onDelete 当delete时触发函数
         * @param extendable 是否可以拓展
         * @returns 
         */
        constructor(type: new () => T, initSize: number = 32, onDelete: Nullable<(obj: T) => void> = null, extendable = true) {
            if (!type) {
                console.warn(`type is null`);
                return;
            }
            this._onDelete = onDelete;
            this._poolList = [];
            this._extendable = extendable;
            this._type = type;
            this._size = 0;
            if (initSize > 0) {
                this.extend(initSize);
            }
        }

        /**
         * 拓展池大小
         * @param count 拓展大小
         */
        protected extend(count: number) {
            if (count < 2) count = 2;
            const t = this._type;
            for (let i = 0; i < count; i++) {
                const obj = new t();
                (obj as any)[Pool.inPoolTag] = true;
                this._poolList.push(new t());
            }
            this._size += count;
        }

        /** 池是否可以拓展 */
        public get extendable() { return this._extendable; }
        /** 池中元素数量 */
        public get size() { return this._size; }

        /**
         * 获取一个对象
         * @returns T 类型的对象
         */
        public new(): Nullable<T> {
            let result = this._poolList.pop();
            if (!result) {
                if (!this._extendable) return null;
                this.extend(this._size);
                result = this._poolList.pop();
            }
            delete (result as any)[Pool.inPoolTag];
            return result as T;
        }

        /**
         * 回收一个对象
         * @param obj T 类型的对象
         */
        public delete(obj: T) {
            if (!obj) return;
            if ((obj as any)[Pool.inPoolTag]) {
                console.warn(`obj It's already in the pool`);
                return;
            }
            (obj as any)[Pool.inPoolTag] = true;
            this._poolList.push(obj);
            if (this._onDelete) this._onDelete(obj);
        }

    }

}